<?php

class Skjb_Directory_Iterator implements SeekableIterator, Countable, ArrayAccess
{
    protected $_dir = null;

    protected $_rows = array();
    
    protected $_data = array();
    
    protected $_count = 0;
    
    protected $_pointer = 0;
    
    protected $_filter = 3;
    
    protected $_ignore = array();
    
    const FILTER_FILES = 1;
    
    const FILTER_DIRECTORIES = 2;
    
    const FILTER_ALL = 3;
    
    public function __construct($dir, $filter = self::FILTER_ALL, $ignore = array())
    {
        $this->_dir = $dir;
        $this->_filter = $filter;
        $this->_ignore = $ignore;
        
        $includeAll = $this->_filter == self::FILTER_ALL;
        $includeFiles = $this->_filter == self::FILTER_ALL || $this->_filter == self::FILTER_FILES;
        $includeDirectories = $this->_filter == self::FILTER_ALL || $this->_filter == self::FILTER_DIRECTORIES;
        
        $rows = scandir($this->_dir->path);
        foreach ($rows as $row) {
            if ($row != '.' && $row != '..') {
                $fullPath = $this->_dir->path . DIRECTORY_SEPARATOR . $row;
                $inIgnore = in_array($row, $this->_ignore);
                if (!$inIgnore && ($includeAll || ($includeFiles && is_file($fullPath)) || ($includeDirectories && is_dir($fullPath)))) {
                    $this->_data[] = $row;
                }
            }
        }
        
        $this->_count = count($this->_data);
    }
    
    public function rewind()
    {
        $this->_pointer = 0;
        return $this;
    }
    
    public function current()
    {
        if ($this->valid() === false) {
            return null;
        }

        if (empty($this->_rows[$this->_pointer])) {
            $path = $this->_dir->path . DIRECTORY_SEPARATOR . $this->_data[$this->_pointer];
            if (is_dir($path)) {
                $this->_rows[$this->_pointer] = new Skjb_Directory($path);
            } elseif (is_file($path)) {
                $this->_rows[$this->_pointer] = new Skjb_File($path);
            }
        }
        return $this->_rows[$this->_pointer];
    }
    
    public function key()
    {
        return $this->_pointer;
    }

    public function next()
    {
        ++$this->_pointer;
    }
    
    public function valid()
    {
        return $this->_pointer < $this->_count;
    }
    
    public function count()
    {
        return $this->_count;
    }

    public function seek($position)
    {
        $position = (int)$position;
        if ($position < 0 || $position >= $this->_count) {
            throw new Zend_Exception('Illegal index ' . $position);
        }
        $this->_pointer = $position;
        return $this;
    }

    public function offsetExists($offset)
    {
        return isset($this->_data[(int)$offset]);
    }

    public function offsetGet($offset)
    {
        $this->_pointer = (int)$offset;
        return $this->current();
    }

    public function offsetSet($offset, $value)
    {
    }

    public function offsetUnset($offset)
    {
    }

    public function getRow($position, $seek = false)
    {
        $key = $this->key();
        try {
            $this->seek($position);
            $row = $this->current();
        } catch (Zend_Exception $e) {
            throw new Zend_Exception('No row could be found at position ' . (int)$position);
        }
        if ($seek == false) {
            $this->seek($key);
        }
        return $row;
    }
}